﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Ymatou.PerfMonitorClient;
using Ymatou.User.Dto.Auth;
using YmtAuth.Common.Extend;
using YmtAuth.Common.Utility;
using YmtAuth.Domain.Model.Token;
using YmtAuth.Domain.Model.YmatouUser;
using YmtAuth.Domain.Shard;
using YmtSystem.CrossCutting;

namespace YmtAuth.Domain.DomainService
{
    public class AuthResponse
    {
        public int Code { get; set; }
        public int UserId { get; set; }
        public string Message { get; set; }
    }
    public abstract class AbstractAuthTokenStrategy
    {
        /// <summary>
        /// 执行具体的业务token验证
        /// </summary>
        /// <param name="tokenString"></param>
        /// <param name="userToken"></param>
        /// <returns></returns>
        protected abstract AuthResponse Verify(UserToken userToken);
        /// <summary>
        /// 执行token验证；200：验证成功；-80：IP黑名单,-100：token为空，-120：解密异常；-140：解密后userid错误；-160：认证库不存在token；-180：token携带的userid和
        /// 认证库的token userid不匹配
        /// </summary>
        /// <param name="tokenId"></param>
        /// <param name="userTokenFunc"></param>
        /// <returns></returns>
        public virtual AuthResponse ExecuteTokenVerify(string tokenId, Func<string, UserToken> userTokenFunc
            , Func<int, UserStates> userStateFunc, Func<bool> ipblacklistFunc)
        {
            //首先检查是否为IP黑名单用户
            if (ipblacklistFunc()) return new AuthResponse { Code = -80, Message = "Token不能为空" };
            //参数检查
            if (string.IsNullOrEmpty(tokenId)) return new AuthResponse { Code = -100, Message = "Token不能为空" };
            var tmpTokenInfo = new UserToken();
            //解密
            tmpTokenInfo.DecryptToken(tokenId);
            //检查解密后的原始token
            if (string.IsNullOrEmpty(tmpTokenInfo.RawToken)) return new AuthResponse { Code = -120, Message = "Token解密错误" };
            //检查解密后的UserID
            if (tmpTokenInfo.UserId <= 0) return new AuthResponse { Code = -140, Message = "Token用户ID错误" };
            //获取认证库的token
            var rawTokenInfo = userTokenFunc(tmpTokenInfo.RawToken);
            if (rawTokenInfo == null)
            {
                using (var mm = MethodMonitor.New("TokenVerify_NotFind"))
                {
                }
                return new AuthResponse { Code = -160, Message = "Token不存在" };
            }
            //检查tokenUserID和数据库UserID是否匹配
            if (!rawTokenInfo.VerifyTokenUserIsMatch(tmpTokenInfo.UserId)) return new AuthResponse { Code = -180, Message = "Token用户ID不匹配" };
            //检查用户是否被锁定
            if (userStateFunc(rawTokenInfo.UserId) != UserStates.Normal) return new AuthResponse { Code = -200, Message = "用户被锁定" };
            //执行具体验证策略
            var result = Verify(rawTokenInfo);
            return new AuthResponse { Code = result.Code, UserId = result.UserId, Message = result.Message };
        }

        /// <summary>
        /// 执行token签名验证（老版逻辑）
        /// 200：验证成功；-80：IP黑名单,-100：token为空，-120：解密异常；-140：解密后userid错误；-160：认证库不存在token；-180：token携带的userid和
        /// 认证库的token userid不匹配
        /// </summary>
        /// <param name="tokenString"></param>
        /// <param name="userTokenFunc"></param>
        /// <param name="userStateFunc"></param>
        /// <returns></returns>
        public virtual AuthResponse ExecuteTokenSignVerify(string originalVal, string sign, Func<string, UserToken> userTokenFunc
          , Func<int, UserStates> userStateFunc, Func<bool> ipblacklistFunc, string requestId)
        {
            //首先检查是否为IP黑名单用户
            if (ipblacklistFunc()) return new AuthResponse { Code = -80, Message = "Token不能为空" };
            //参数检查
            if (string.IsNullOrEmpty(originalVal) || string.IsNullOrEmpty(sign)) return new AuthResponse { Code = -100, Message = "签名窜不能为空" };
            //构建token&验证签名
            var tmpTokenInfo = new UserToken(originalVal, sign);

            var verifySign = Action_Extend.ActionWatch(() => tmpTokenInfo.VerifySign(), requestId + ", VerifySign");

            if (verifySign.Item1 != LoginResponseCode.OK)
            {
                return new AuthResponse { Code = -(int)verifySign.Item1, Message = verifySign.Item2 };
            }
            //获取数据库的token
            var rawTokenInfo = userTokenFunc(tmpTokenInfo.RawToken);
            if (rawTokenInfo == null) return new AuthResponse { Code = -160, Message = "Token不存在" };
            //验证用户token
            if (!rawTokenInfo.VerifyTokenUserIsMatch(tmpTokenInfo.UserId)) return new AuthResponse { Code = -180, UserId = rawTokenInfo.UserId, Message = "Token用户ID不匹配" };
            //检查是否黑名单用户
            if (userStateFunc(rawTokenInfo.UserId) != UserStates.Normal) return new AuthResponse { Code = -200, UserId = rawTokenInfo.UserId, Message = "用户被锁定" };
            //执行具体验证
            var result = Verify(rawTokenInfo);
            return new AuthResponse { Code = result.Code, UserId = result.UserId, Message = result.Message };
        }
    }
    //以下实现不同具体验证策略
    //网站站验证策略
    public class MainAuthToken : AbstractAuthTokenStrategy
    {
        protected override AuthResponse Verify(UserToken userToken)
        {
            return new AuthResponse { Code = 200, UserId = userToken.UserId };
        }
    }
    //扫货神器验证策略
    public class AppAuthToken : AbstractAuthTokenStrategy
    {
        protected override AuthResponse Verify(UserToken userToken)
        {
            //如果已过期
            if (userToken.TokenIsExpired())
            {
                var timeOutString = ConfigurationManager.AppSettings["ExtendTokenTimeOut"].Split(new char[] { ';' });
                return new AuthResponse { Code = 210,UserId=userToken.UserId };
            }
            return new AuthResponse { Code = 200, UserId = userToken.UserId };
        }
    }
    //码头wap验证策略
    public class MatouAppAuthToken : AbstractAuthTokenStrategy
    {
        protected override AuthResponse Verify(UserToken userToken)
        {
            return new AuthResponse { Code = 200, UserId = userToken.UserId };
        }
    }
}
